package com.sjgs.gis.config;

import com.sjgs.common.utils.KryoUtils;
import com.sjgs.common.utils.UUIDUtils;
import com.sjgs.gis.domain.Node;
import com.sjgs.gis.domain.enumeration.NodeStatus;
import com.sjgs.gis.fs.store.DefaultKVStore;
import org.rocksdb.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;


import java.util.Properties;

import static com.sjgs.common.Constants.*;

@Configuration
@AutoConfigureBefore({KVStoreConfiguration.class})
public class ClusterConfiguration {

    @Bean(name = "currentNode")
    @SuppressWarnings("all")
    Node initNode(ConfigurableEnvironment environment,
                  EurekaInstanceConfigBean instance,
                  InetUtils inetUtils,
                  DefaultKVStore kvstore,
                  @Value("${spring.application.name}") String serviceId,
                  @Value("${spring.application.sname}") String sname,
                  @Value("${grpc.server.port}") Integer grpcport,
                  @Value("${server.port}") Integer port
    ) {
        Node node = null;
        RocksDB sysdb = kvstore.getDb();
        ColumnFamilyHandle clusterHandle = kvstore.getColumnFamilyHandle(CF_CLUSTER);
        String newId = sname + SEP + Long.toUnsignedString(UUIDUtils.nextShortId(), 32);
        String instanceid = newId;
        String host = inetUtils.findFirstNonLoopbackAddress().getHostAddress();
        Properties props = new Properties();
        if (sysdb != null) {
            RocksIterator iter = sysdb.newIterator(clusterHandle);
            for (iter.seek((sname + SEP).getBytes()); iter.isValid(); iter.next()) {
                instanceid = new String(iter.key());
                node = KryoUtils.deserializeObject(iter.value(), Node.class);
                node.setHost(host);
                node.setPort(port);
                break;
            }
            if (instanceid.equals(newId)) {
                node = new Node(instanceid, serviceId, host, port);
                node.setStatus(NodeStatus.N);
            }
            //update host
            try {
                byte[] value = KryoUtils.serializeObject(node);
                sysdb.put(clusterHandle, instanceid.getBytes(), value);
            } catch (RocksDBException e) {
                ;
            }
        }
        instance.setInstanceId(instanceid);
        props.put("eureka.instance.instance-id", instanceid);
        environment.getPropertySources().addLast(new PropertiesPropertySource("applicationConfig: [classpath:/application-cluster.yml]", props));
        return node;
    }
}
